#include "wiota_test.h"
#include "config_api.h"
#include "factory.h"
#include "factory_api.h"
#include "rthw.h"
#include "uc_coding.h"
#include "uc_wiota_api.h"
#include "wiota_app.h"
#include "wiota_flashing.h"
#include "wiota_freq.h"
#include <rtthread.h>

#define DBG_ENABLE
#define DBG_SECTION_NAME "wiota_test"
#include "uc_log.h"

#define SYNC_FLASH_FAIL "sync flash fail"
#define WIOTA_FLASH_FAIL "ap flash fail"
#define WIOTA_SYNC_FLASH_FAIL "ap&sync flash fail"
#define WIOTA_APP_INIT_FAIL "app init fail"
#define WIOTA_APP_RUN_FAIL "app run fail"
#define WIOTA_RECV_FAIL "recv fail"
#define WIOTA_TEST_SUC "wiota test suc"
#define GPS_TS_TEST_SUC "gps_ts test suc"
#define GPS_TS_TEST_FAIL "no gps time received"
#define SYNC_TS_TEST_SUC "sync_ts test suc"
#define SYNC_TS_TEST_FAIL "no sync time received"
#define WIOTA_RECV_TEST_CNT 5
#define TS_CHECK_DELAY (60 * 1000)
#define WIOTA_CHECK_DELAY (20 * 1000)

#define CMD_TS_SUC 0x01
#define CMD_TS_TIMEOUT 0x02
#define CMD_WIOTA_SUC 0x03
#define CMD_WIOTA_TIMEOUT 0x04

static unsigned char g_cur_ts_mode = UC_TS_NONE;
static signed char g_ul_rssi[WIOTA_RECV_TEST_CNT] = {0};
static signed char g_dl_rssi[WIOTA_RECV_TEST_CNT] = {0};
static signed char g_dl_snr[WIOTA_RECV_TEST_CNT] = {0};
static signed char g_avg_ul_rssi = 0;
static signed char g_avg_dl_rssi = 0;
static signed char g_avg_dl_snr = 0;
static unsigned char g_recv_index = 0;
static unsigned int g_sync_start_time = 0;
static unsigned int g_gps_start_time = 0;
static unsigned int g_wiota_start_time = 0;
static struct rt_work *g_wiota_work = RT_NULL;
static struct rt_work *g_sync_work = RT_NULL;
static struct rt_work *g_gps_work = RT_NULL;
static rt_mq_t g_wiota_test_mq = RT_NULL;

static void wiota_factory_send_callback(uc_send_recv_t *result)
{
    // do nothing
}

static void wiota_factory_recv_callback(uc_recv_detail_t *recv_detail)
{
    unsigned char *decode_data = RT_NULL;
    unsigned int decode_data_len = 0;
    app_ps_header_t ps_header = {0};
    app_ps_iote_state_update_t *iote_state = RT_NULL;
    wiota_freq_cfg_t *freq_cfg = uc_static_get_wiota_freq_cfg();

    if (g_recv_index >= WIOTA_RECV_TEST_CNT)
    {
        return;
    }
    app_data_decoding(recv_detail->data, recv_detail->data_len, &decode_data, &decode_data_len, &ps_header);

    RT_ASSERT(decode_data != RT_NULL);
    RT_ASSERT(decode_data_len > 0);

    if (ps_header.cmd_type == AUTHENTICATION_REQ)
    {
        unsigned char *output_data;
        unsigned int output_len;
        unsigned int gw_dev_id = uc_static_get_gateway_base_cfg()->dev_id;
        app_ps_auth_res_t auth_res = {0};
        app_ps_header_t ps_header = {0};

        auth_res.connect_index.state = AUTHENTICATION_SUC;
        auth_res.connect_index.time_slot_fn = 1;
        auth_res.wiota_id = 0x80000043;
        rt_memcpy(auth_res.freq_list, freq_cfg->freq_list, APP_MAX_FREQ_LIST_NUM);

        ps_header.cmd_type = AUTHENTICATION_RES;
        if (0 != app_data_coding(&ps_header, (unsigned char *)&auth_res, sizeof(app_ps_auth_res_t), &output_data, &output_len))
        {
            TRACE_E("%s line %d coding error", __FUNCTION__, __LINE__);
            return;
        }
        uc_wiota_send_data(output_data, output_len, recv_detail->user_id, 1000, wiota_factory_send_callback, NULL);
        rt_free(output_data);
    }
    else if (ps_header.cmd_type == IOTE_STATE_UPDATE)
    {
        iote_state = (app_ps_iote_state_update_t *)decode_data;

        unsigned int recv_data_id = recv_detail->user_id;
        g_ul_rssi[g_recv_index] = recv_detail->rssi;
        g_dl_rssi[g_recv_index] = ~(iote_state->rssi - 1);
        g_dl_snr[g_recv_index] = (signed char)iote_state->snr;
        TRACE_D("recv data id %u, rssi %d %d, snr %d", recv_data_id, g_dl_rssi[g_recv_index], g_ul_rssi[g_recv_index], g_dl_snr[g_recv_index]);
        g_recv_index++;
        if (g_recv_index == WIOTA_RECV_TEST_CNT)
        {
            signed short ul_rssi_sum = 0;
            signed short dl_rssi_sum = 0;
            signed short dl_snr_sum = 0;

            for (int i = 0; i < WIOTA_RECV_TEST_CNT; i++)
            {
                ul_rssi_sum += g_ul_rssi[i];
                dl_rssi_sum += g_dl_rssi[i];
                dl_snr_sum += g_dl_snr[i];
            }

            g_avg_dl_rssi = dl_rssi_sum / WIOTA_RECV_TEST_CNT;
            g_avg_dl_snr = dl_snr_sum / WIOTA_RECV_TEST_CNT;
            g_avg_ul_rssi = ul_rssi_sum / WIOTA_RECV_TEST_CNT;

            unsigned int cmd = CMD_WIOTA_SUC;
            rt_mq_send(g_wiota_test_mq, (void *)&cmd, 4);
        }
    }

    rt_free(recv_detail->data);
    rt_free(decode_data);
}

static void wiota_factory_ts_info_callback(uc_ts_info_t *ts_info)
{
    unsigned int cmd = CMD_TS_SUC;

    if (ts_info->ts_state == TIME_SERVICE_INIT_END ||
        ts_info->ts_state == TIME_SERVICE_ALIGN_END)
    {
        rt_mq_send(g_wiota_test_mq, (void *)&cmd, 4);
    }
}

static int wiota_test_fail_before_start(char *remark)
{
    factory_test_result(WIOTA_TEST, factory_get_key(WIOTA_TEST), FACTORY_TEST_FAIL, remark);
    facotry_result_output(WIOTA_TEST, 1, g_wiota_start_time);

    factory_test_result(GPS_TS_TEST, factory_get_key(GPS_TS_TEST), FACTORY_TEST_FAIL, remark);
    facotry_result_output(GPS_TS_TEST, 1, g_gps_start_time);

    factory_test_result(SYNC_TS_TEST, factory_get_key(SYNC_TS_TEST), FACTORY_TEST_FAIL, remark);
    facotry_result_output(SYNC_TS_TEST, 1, g_sync_start_time);
}

static void wiota_rs_check_work(struct rt_work *work, void *work_data)
{
    unsigned int cmd = CMD_WIOTA_TIMEOUT;

    rt_mq_send(g_wiota_test_mq, (void *)&cmd, 4);

    rt_free(g_wiota_work);
    g_wiota_work = RT_NULL;
}

static void wiota_sync_ts_check_work(struct rt_work *work, void *work_data)
{
    unsigned int cmd = CMD_TS_TIMEOUT;

    rt_mq_send(g_wiota_test_mq, (void *)&cmd, 4);

    rt_free(g_sync_work);
    g_sync_work = RT_NULL;
}

static void wiota_gps_ts_check_work(struct rt_work *work, void *work_data)
{
    unsigned int cmd = CMD_TS_TIMEOUT;

    rt_mq_send(g_wiota_test_mq, (void *)&cmd, 4);

    rt_free(g_gps_work);
    g_gps_work = RT_NULL;
}

static void wiota_gps_ts_test(void)
{
    uc_wiota_sync_assistant_power_off();
    uc_wiota_time_service_stop();
    uc_wiota_set_time_service_func(UC_TS_SYNC_ASSISTANT - 1, 0);
    uc_wiota_set_time_service_func(UC_TS_GPS - 1, 1);
    uc_wiota_time_service_start();
    g_cur_ts_mode = UC_TS_GPS;

    g_gps_start_time = facotry_start_output(GPS_TS_TEST);
    g_gps_work = rt_malloc(sizeof(struct rt_work));
    RT_ASSERT(g_gps_work);
    rt_work_init(g_gps_work, wiota_gps_ts_check_work, RT_NULL);
    rt_work_submit(g_gps_work, TS_CHECK_DELAY * 2);
    TRACE_D("submit gps_work, delay %u", TS_CHECK_DELAY * 2);
}

static void wiota_gps_ts_test_stop(void)
{
    uc_wiota_time_service_stop();
    uc_wiota_set_time_service_func(UC_TS_GPS - 1, 0);
    g_cur_ts_mode = UC_TS_NONE;

    TRACE_D("gps_test stop");
}

static void wiota_factory_test_entry(void *parameter)
{
    unsigned int cmd = 0xff;
    factory_test_state_e state = FACTORY_TEST_DEFAULT;
    char remark[REMARK_LEN] = {0};

    while (1)
    {
        if (RT_EOK != rt_mq_recv(g_wiota_test_mq, (void *)&cmd, 4, RT_WAITING_FOREVER))
        {
            continue;
        }

        switch (cmd)
        {
        case CMD_WIOTA_SUC:
            factory_get_result(WIOTA_TEST, RT_NULL, &state, RT_NULL);
            if (state != FACTORY_TEST_FAIL) // 如果成功时，已经失败，说明超时，也算失败
            {
                // 收发测试成功，取消超时检测工作项
                if (g_wiota_work)
                {
                    rt_work_cancel(g_wiota_work);
                }
                rt_snprintf(remark, REMARK_LEN, "%s %d %d %d", WIOTA_TEST_SUC, g_avg_dl_rssi, g_avg_ul_rssi, g_avg_dl_snr);
                factory_test_result(WIOTA_TEST, factory_get_key(WIOTA_TEST), FACTORY_TEST_SUCCESS, remark);
                TRACE_I("@%s test suc, %d %d %d time %d ms", factory_get_key(WIOTA_TEST),
                        g_avg_dl_rssi, g_avg_ul_rssi, g_avg_dl_snr, rt_tick_get() - g_wiota_start_time);
            }
            break;

        case CMD_WIOTA_TIMEOUT:
            factory_get_result(WIOTA_TEST, RT_NULL, &state, RT_NULL);
            if (state != FACTORY_TEST_SUCCESS) // 如果已经超时了，还未成功，就算失败
            {
                rt_snprintf(remark, REMARK_LEN, "%s %d", WIOTA_RECV_FAIL, g_recv_index);
                factory_test_result(WIOTA_TEST, factory_get_key(WIOTA_TEST), FACTORY_TEST_FAIL, WIOTA_RECV_FAIL);
                facotry_result_output(WIOTA_TEST, 1, g_wiota_start_time);
            }
            break;

        case CMD_TS_SUC:
            if (g_cur_ts_mode == UC_TS_SYNC_ASSISTANT)
            {
                // 同步助手测试成功，取消超时检测工作项
                if (g_sync_work)
                {
                    rt_work_cancel(g_sync_work);
                }
                factory_get_result(SYNC_TS_TEST, RT_NULL, &state, RT_NULL);
                if (state != FACTORY_TEST_FAIL) // 如果成功时，已经失败，说明超时，也算失败
                {
                    factory_test_result(SYNC_TS_TEST, factory_get_key(SYNC_TS_TEST), FACTORY_TEST_SUCCESS, SYNC_TS_TEST_SUC);
                    facotry_result_output(SYNC_TS_TEST, 0, g_sync_start_time);
                }

                // 由于先测试的同步助手，不管成功还是失败都切为GPS测试
                wiota_gps_ts_test();
            }
            else if (g_cur_ts_mode == UC_TS_GPS)
            {
                // GPS测试成功，取消超时检测工作项
                if (g_gps_work)
                {
                    rt_work_cancel(g_gps_work);
                }
                factory_get_result(GPS_TS_TEST, RT_NULL, &state, RT_NULL);
                if (state != FACTORY_TEST_FAIL) // 如果成功时，已经失败，说明超时，也算失败
                {
                    factory_test_result(GPS_TS_TEST, factory_get_key(GPS_TS_TEST), FACTORY_TEST_SUCCESS, GPS_TS_TEST_SUC);
                    facotry_result_output(GPS_TS_TEST, 0, g_gps_start_time);
                }

                // 成功后停止
                wiota_gps_ts_test_stop();
            }
            break;

        case CMD_TS_TIMEOUT:
            if (g_cur_ts_mode == UC_TS_SYNC_ASSISTANT)
            {
                factory_get_result(SYNC_TS_TEST, RT_NULL, &state, RT_NULL);
                if (state != FACTORY_TEST_SUCCESS)
                {
                    factory_test_result(SYNC_TS_TEST, factory_get_key(SYNC_TS_TEST), FACTORY_TEST_FAIL, SYNC_TS_TEST_FAIL);
                    facotry_result_output(SYNC_TS_TEST, 1, g_sync_start_time);
                }

                // 由于先测试的同步助手，不管成功还是失败都切为GPS测试
                wiota_gps_ts_test();
            }
            else if (g_cur_ts_mode == UC_TS_GPS)
            {
                factory_get_result(GPS_TS_TEST, RT_NULL, &state, RT_NULL);
                if (state != FACTORY_TEST_SUCCESS)
                {
                    factory_test_result(GPS_TS_TEST, factory_get_key(GPS_TS_TEST), FACTORY_TEST_FAIL, GPS_TS_TEST_FAIL);
                    facotry_result_output(GPS_TS_TEST, 1, g_gps_start_time);
                }

                // 超时后停止
                wiota_gps_ts_test_stop();
            }
            break;

        default:
            break;
        }
    }
}

int wiota_test(void)
{
    TRACE_I("factory wiota test start");
    int ts_mode = UC_TS_SYNC_ASSISTANT; // 默认先测试同步助手

    // 测试前，清空测试结果
    factory_test_result(WIOTA_TEST, factory_get_key(WIOTA_TEST), FACTORY_TEST_DEFAULT, "null");
    factory_test_result(GPS_TS_TEST, factory_get_key(GPS_TS_TEST), FACTORY_TEST_DEFAULT, "null");
    factory_test_result(SYNC_TS_TEST, factory_get_key(SYNC_TS_TEST), FACTORY_TEST_DEFAULT, "null");

    // 检查AP和同步助手固件是否需要重刷
    g_sync_start_time = facotry_start_output(SYNC_TS_TEST);
    g_gps_start_time = facotry_start_output(GPS_TS_TEST);
    g_wiota_start_time = facotry_start_output(WIOTA_TEST);
    int res = wiota_flashing();
    if (res == 1) // 同步助手刷机失败直接测试GPS，不在测试同步助手了，但wiota还要继续测试
    {
        factory_test_result(SYNC_TS_TEST, factory_get_key(SYNC_TS_TEST), FACTORY_TEST_FAIL, SYNC_FLASH_FAIL);
        facotry_result_output(SYNC_TS_TEST, 1, g_sync_start_time);
        ts_mode = UC_TS_GPS;
    }
    else if (res == 2) // wiota刷机失败，都不用测了，全部返回失败
    {
        wiota_test_fail_before_start(WIOTA_FLASH_FAIL);
        return 1;
    }
    else if (res == 3)
    {
        wiota_test_fail_before_start(WIOTA_SYNC_FLASH_FAIL);
        return 2;
    }

    // WIoTa APP通信方式初始化
    if (0 != wiota_app_init())
    {
        TRACE_E("wiota app init fail");
        wiota_test_fail_before_start(WIOTA_APP_INIT_FAIL);
        return 3;
    }

    wiota_scan_freq();

    // 以ts_mode开启测试
    uc_static_get_wiota_cfg()->ts_cfg.ts_mode = ts_mode;
    g_cur_ts_mode = ts_mode;

    // 启动WIoTa
    if (0 != wiota_app_run(1))
    {
        uc_wiota_reboot();
        TRACE_E("wiota run fail");
        wiota_test_fail_before_start(WIOTA_APP_RUN_FAIL);
        return 4;
    }

    // 工厂模式采用直连功率设为0dbm
    uc_wiota_set_ap_tx_power(0);
    uc_wiota_set_aagc_idx(0);
    // 覆盖wiota_app_run里面的回调函数指针
    uc_wiota_register_recv_data_detail_callback(wiota_factory_recv_callback);
    uc_wiota_register_time_service_info_callback(wiota_factory_ts_info_callback);

    // WIoTa收发测试开始
    g_wiota_start_time = facotry_start_output(WIOTA_TEST);
    // 延迟WIOTA_CHECK_DELAY检测WIoTa是否成功
    g_wiota_work = rt_malloc(sizeof(struct rt_work));
    RT_ASSERT(g_wiota_work);
    rt_work_init(g_wiota_work, wiota_rs_check_work, RT_NULL);
    rt_work_submit(g_wiota_work, WIOTA_CHECK_DELAY);
    TRACE_D("submit wiota_work, delay %u", WIOTA_CHECK_DELAY);

    // 同步助手测试开始
    if (g_cur_ts_mode == UC_TS_SYNC_ASSISTANT) // 该条件不满足时，说明同步助手刷机失败不需要测试了
    {
        g_sync_start_time = facotry_start_output(SYNC_TS_TEST);
        // 延迟TS_CHECK_DELAY检测同步助手授时是否成功
        g_sync_work = rt_malloc(sizeof(struct rt_work));
        RT_ASSERT(g_sync_work);
        rt_work_init(g_sync_work, wiota_sync_ts_check_work, RT_NULL);
        rt_work_submit(g_sync_work, TS_CHECK_DELAY / 2);
        TRACE_D("submit sync_work, delay %u", TS_CHECK_DELAY / 2);
    }
    g_wiota_test_mq = rt_mq_create("wiota_mq", sizeof(unsigned int), 16, RT_IPC_FLAG_FIFO);
    RT_ASSERT(g_wiota_test_mq);

    rt_thread_t wiota_fac_handler = rt_thread_create("wiota_fac",
                                                     wiota_factory_test_entry,
                                                     RT_NULL,
                                                     2048,
                                                     RT_THREAD_PRIORITY_MAX / 2 - 2,
                                                     5);
    RT_ASSERT(wiota_fac_handler);
    rt_thread_startup(wiota_fac_handler);

    return 0;
}

int wiota_test_result(int test_type)
{
    factory_test_state_e state = FACTORY_TEST_DEFAULT;

    factory_get_result(test_type, RT_NULL, &state, RT_NULL);

    if (state == FACTORY_TEST_SUCCESS)
    {
        return 0;
    }
    else if (state == FACTORY_TEST_FAIL)
    {
        return 1;
    }
    else
    {
        return FACTORY_TEST_DEF_VALUE;
    }
}

#if 1
int wiota_factory_test_cmd(void)
{
    if (0 != wiota_test())
    {
        return 1;
    }

    // 延时20s
    rt_thread_mdelay(20000);

    return 0;
}
MSH_CMD_EXPORT_ALIAS(wiota_factory_test_cmd, wiota_test, factory test wiota send recv);
#endif